package Thread;

import java.util.Scanner;

/**线程安全问题：内存的可见性
一个线程读，一个进行修改，修改线程修改的值，并没有被读线程读到    volatile解决*/
public class demo21 {

    // private static int flag = 0;
    private static volatile int flag = 0;   //  这样的变量读取操作，就不会被编译器进行优化了
    // volatile解决了内存可见性问题
    public static void main(String[] args) {
        Thread t1 = new Thread(()->{

            while(flag == 0) {
                // 编译器优化的侧面证明（从 从内存加载优化到从寄存器加载）
                try {
                    Thread.sleep(1);    // 使循环的次数大幅度降低，sleep消耗的时间，比加载到内存中高了不少，优化已经不重要了，主要矛盾转移了
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("t1 线程结束");
        });

        Thread t2 = new Thread(()->{
            Scanner scanner = new Scanner(System.in);
            System.out.println("输出flag的值");
            flag = scanner.nextInt();
        });
        t1.start();
        t2.start();
    }
}

// 问题的产生：编译器优化。虽然声称优化操作，但是在多线程程序中，编译器可能出现失误

/*括号中的flag == 0是一个条件判定，类似与compare这样的指令（条件跳转）
* 1.先读取flag的值。2.进行条件跳转      但是读取值时间开销比compare大得多
* 执行过程中，jvm感受到读取的flag都是0，因为flag改变需要用户输入。
* 既然都是0，为什么执行这么多次读内存，所以优化为读取寄存器结果（0）操作
* 于是当用户输入新的值后，t1线程感知不到*/